package com.mrd.gtimp.business.service;

import com.mrd.base.BaseBiz;
import com.mrd.gtimp.business.entity.Declaration;
import com.mrd.gtimp.business.entity.hongbao.DeclarationHongbaoRecord;
import com.mrd.gtimp.business.entity.hongbao.DeclarationHongbaoState;
import com.mrd.gtimp.business.repository.hongbao.DeclarationHongbaoRecordDao;
import com.mrd.gtimp.business.repository.hongbao.DeclarationHongbaoStateDao;
import com.mrd.gtimpframe.entity.Dictionary;
import com.mrd.gtimpframe.entity.DictionaryGroup;
import com.mrd.gtimpframe.repository.DictionaryGroupMapper;
import com.mrd.gtimpframe.repository.DictionaryMapper;
import com.mrd.gtimpframe.service.DictionaryGroupService;
import com.mrd.gtimpframe.service.DictionaryService;
import com.mrd.projects.weixinapi.App;
import com.mrd.projects.weixinapi.entity.HongBaoTask;
import com.mrd.projects.weixinapi.util.BizUtil;
import com.mrd.projects.weixinapi.util.WeixinApiConfigUtil;
import com.mrd.redis.JedisClientClusterImpl;
import com.mrd.spring.repository.BaseRepository;

import com.mrd.util.StringUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.task.SyncTaskExecutor;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Random;
import java.util.concurrent.LinkedBlockingDeque;

import javax.annotation.Resource;
import javax.transaction.Transactional;

/**
 * Created by dengdc on 2016/12/28.
 */
@Service
public class HongbaoBiz extends BaseBiz {
    private Logger logger = Logger
            .getLogger(HongbaoBiz.class);
    private Logger hongbaoLogger = Logger
            .getLogger("！！！HongbaoTaskError！！！");
    @Resource
    private DeclarationHongbaoStateDao declarationHongbaoStateDao;
    @Resource
    private DeclarationHongbaoRecordDao declarationHongbaoRecordDao;

    private final Queue<DeclarationHongbaoRecord> hongbaoQueue = new LinkedBlockingDeque<>();
    @Resource
    private DictionaryMapper dictionaryMapper;
    @Resource
    private DictionaryGroupService dictionaryGroupService;

    private boolean taskIsAlive = false;

    // @PostConstruct
    // public void init() {
    // if(shouldSendHongbao()) {
    // invokeResendTask();
    // }
    // }

    public void invokeResendTask() {
        List<DeclarationHongbaoRecord> unsendRecords = declarationHongbaoRecordDao
                .findBySended(Boolean.FALSE);
        hongbaoLogger.info("找到" + unsendRecords.size() + "个未发送成功的红包。");
        synchronized (hongbaoQueue) {
            hongbaoQueue.clear();
            hongbaoQueue.addAll(unsendRecords);
        }
        if (!hongbaoQueue.isEmpty()) {
            newTaskToSendHongbao();
        }
    }

    /**
     * 创建新的任务发送红包
     */
    private void newTaskToSendHongbao() {
        if (taskIsAlive) {
            return;
        }
        new SyncTaskExecutor().execute(() -> {
            taskIsAlive = true;
            int times = 0;
            while (!hongbaoQueue.isEmpty()) {
                // 假如一直发送不成功会一直发送
                sendHongbao(hongbaoQueue.peek());
                times++;
                if (times == 15) {
                    break;
                }
            }
            taskIsAlive = false;
        });
    }

    /**
     * 是否应该发送红包
     */
    public boolean shouldSendHongbao() {
        List<DeclarationHongbaoState> stateList = declarationHongbaoStateDao.findAll();
        if (CollectionUtils.isNotEmpty(stateList)) {
            DeclarationHongbaoState hongbaoState = stateList.get(0);
            Date now = new Date();
            if (hongbaoState.getBeginTime().before(now) && hongbaoState.getEndTime().after(now)
                    && hongbaoState.getValid()) {
                return true;
            }
        }
        return false;
    }

    /**
     * 发送红包
     */
    @Transactional
    public void sendHongBao(Declaration declaration) {
        if (shouldSendHongbao()) {
            String customerComName = declaration.getCustomer().getName();
            if(customerComName.contains("佛山新港") || customerComName.contains("宏达")
            || customerComName.contains("易迅通") || customerComName.contains("鸿港通") || customerComName.contains("佛港") ){
                //去掉宏达的单
                //去掉新港的单
                return;
            }
            if(StringUtils.isNotEmpty(declaration.getDeclaration_port_code()) &&  declaration.getDeclaration_port_code().equals("5189")) {
                sendHongbao(declaration);
            }else{
                return;
            }
        }
    }

    /**
     * 发送红包
     */
    @Transactional
    public void resendHongBao(Declaration declaration) {
        if (declaration == null) {
            logger.info("尝试使用空的报关单发送红包！");
            return;
        }
        System.err.println("来到了补发红包阶段");
        // 生成红包记录
        try {
            DeclarationHongbaoRecord[] records = createRecordByDeclaration(declaration);
            // 发送红包
            try {
                sendHongbao(records[0]);
            } catch (Exception e) {
                logger.info(String.format("首次发送审单员红包失败！【%s】", declaration.getBusinessId()));
            }
            try {
                sendHongbao(records[1]);
            } catch (Exception e) {
                logger.info(String.format("首次发送客户红包失败！【%s】", declaration.getBusinessId()));
            }
        } catch (Exception e) {
            logger.info(String.format("生成红包记录时出现异常！【%s】【%s】", e.getMessage(), declaration.getBusinessId()));
        }


    }

    /**
     * 发送红包
     */
    @Transactional
    private void sendHongbao(Declaration declaration) {
        if (declaration == null) {
            logger.info("尝试使用空的报关单发送红包！");
            return;
        }
        if (!Declaration.DeclarationBusinessState.PASS_STATE.equals(declaration.getState())) {
            String errorFormat = "报关单状态异常，不能发送发送红包。{ID:%s, STATE:%s}";
            logger.info(String.format(errorFormat, declaration.getId(), declaration.getState()));
            return;
        }

        // 生成红包记录
        DeclarationHongbaoRecord[] records = createRecordByDeclaration(declaration);
        // 发送红包
//        sendHongbao(records[0]); //审单员红包
        if(isNotFullCount()){
            sendHongbao(records[1]); //客户红包
        }
    }

    /**
     * 限制红包个数
     */
    private boolean isNotFullCount(){
        String hbPropsCode = "HONGBAO_PROPS";
        String hbMaxCountPorpCode = "HONGBAO_MAX_COUNT";
        String hbCurCountPorpCode = "HONGBAO_CUR_COUNT";
        int maxCount = 1;
        int curCount = 0;
        boolean inLoop = false;
        do {
            DictionaryGroup hbPropsGp = dictionaryGroupService.selectByCode(hbPropsCode);
            List<Dictionary> hbProps = dictionaryMapper.selectByGroupId(hbPropsGp.getId());
            Dictionary hbMaxCountDt = null;
            Dictionary hbCurCountDt = null;
            for (Dictionary hbProp : hbProps) {
                if(hbMaxCountPorpCode.equals(hbProp.getDictionaryCode())){
                    hbMaxCountDt = hbProp;
                }
                if(hbCurCountPorpCode.equals(hbProp.getDictionaryCode())){
                    hbCurCountDt = hbProp;
                }
            }
            assert hbMaxCountDt != null;
            maxCount = Integer.valueOf(hbMaxCountDt.getDescript());
            assert hbCurCountDt != null;
            curCount = Integer.valueOf(hbCurCountDt.getDescript());

            if(curCount < maxCount){
                int updateCount = dictionaryMapper.updateDescript(hbCurCountDt.getId(), String.valueOf(curCount + 1), String.valueOf(curCount));
                if(updateCount == 1){
                    return true;
                }
                curCount ++;
                inLoop = true;
            }else{
                return false;
            }
        }while (inLoop);
        return true;
    }

    /**
     * 使用红包记录发送红包
     *
     * @param record record
     */
    @Transactional
    private void sendHongbao(DeclarationHongbaoRecord record) {
        // 创建红包任务
        HongBaoTask task = createAuditorHongbaoTask(record);

        // 发送红包
        try {
            new App().sendHongBao(task);
            // 修改红包记录状态为已发送,并填充成功时间
            record.setSended(Boolean.TRUE);
            record.setTime(new Date());
            declarationHongbaoRecordDao.save(record);
        } catch (Exception e) {
            String errorFormat = "（DeclarationHongbaoRecord[%s]）首次发送红包失败，进入补发队列...";
            hongbaoQueue.add(record);
            hongbaoLogger.error(String.format(errorFormat, record.getId()));
        }
        if (!hongbaoQueue.isEmpty()) {
            // 激活补发任务
            newTaskToSendHongbao();
        }
    }

    /**
     * 根据报关单创建红包记录
     *
     * @param declaration 报关单
     */
    private DeclarationHongbaoRecord[] createRecordByDeclaration(Declaration declaration) {
        DeclarationHongbaoRecord auditorRecord = new DeclarationHongbaoRecord();
        auditorRecord.setDid(declaration.getId());
        auditorRecord.setBid(declaration.getBusinessId());
        auditorRecord.setAccount(declaration.getValidator().getAccount());
        auditorRecord.setType(DeclarationHongbaoRecord.Type.auditor.value());
        auditorRecord.setAmount(1);
        auditorRecord.setSended(false);

        DeclarationHongbaoRecord customerRecord = new DeclarationHongbaoRecord();
        customerRecord.setDid(declaration.getId());
        customerRecord.setBid(declaration.getBusinessId());
        customerRecord.setAccount(declaration.getValidator().getAccount());
        customerRecord.setType(DeclarationHongbaoRecord.Type.customer.value());
        customerRecord.setAmount(1);
        String creator = declaration.getCreator();
        String modifier = declaration.getModifier();
        if (modifier != null) {
            creator = modifier;
        }
        customerRecord.setAccount(creator);
        customerRecord.setSended(false);

        return new DeclarationHongbaoRecord[]{auditorRecord, customerRecord};
    }

    /**
     * 生产红包任务
     *
     * @param hongbaoRecord 红包记录
     */
    private HongBaoTask createAuditorHongbaoTask(DeclarationHongbaoRecord hongbaoRecord) {
        if (hongbaoRecord.getSended()) {
            return null;
        }
        HongBaoTask task = new HongBaoTask();
        task.setAmount(hongbaoRecord.getAmount().intValue());
        task.setUser_account(hongbaoRecord.getAccount());
        task.setBillno(BizUtil.generateBillNo());
        String templateKey = DeclarationHongbaoRecord.Type.customer.value()
                .equals(hongbaoRecord.getType()) ? DeclarationHongbaoRecord.Type.customer.name()
                : DeclarationHongbaoRecord.Type.auditor.name();
        task.setTemplate_id(WeixinApiConfigUtil.getValue("hongbao." + templateKey));
        task.setBizids(hongbaoRecord.getBid());
        return task;
    }

    @Resource
    @Qualifier("declarationHongbaoRecordDao")
    @Override
    public void setBaseRepository(BaseRepository baseRepository) {
        this.baseRepository = baseRepository;
    }
}

/**
 * 抽奖机 Created by dengdc on 2016/12/29.
 */
class LotteryMachine {
    private static Random random = new Random();

    /**
     * 创建客户奖池
     */
    private static List<Double> createCustomerLotteryPool() {
        List<Double> poolList = new ArrayList<>();
        for (int i = 0; i < 40; i++) {
            poolList.add(2.0);
        }
        for (int i = 0; i < 30; i++) {
            poolList.add(3.0);
        }
        for (int i = 0; i < 20; i++) {
            poolList.add(4.0);
        }
        for (int i = 0; i < 10; i++) {
            poolList.add(5.0);
        }
        // 打乱
        Collections.shuffle(poolList);
        return poolList;
    }

    ;

    /**
     * 创建审核人员的奖池
     */
    private static List<Double> createAuditorLotteryPool() {
        List<Double> poolList = new ArrayList<>();
        for (int i = 0; i < 50; i++) {
            poolList.add(2.0);
        }
        for (int i = 0; i < 50; i++) {
            poolList.add(3.0);
        }
        // 打乱
        Collections.shuffle(poolList);
        return poolList;
    }

    ;

    /**
     * 获取审核人员红包金额
     */
    static Double getAuditorHongbaoAmount() {
        return createAuditorLotteryPool().get(random.nextInt(100));
    }

    /**
     * 获取审核人员红包金额
     */
    static Double getCustomerHongbaoAmount() {
        return createCustomerLotteryPool().get(random.nextInt(100));
    }

    /**
     * 测试方法
     */
    public static void main(String[] args) {
        List<Double> list = new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            list.add(getCustomerHongbaoAmount());
        }
        Map<String, Integer> counter = new HashMap<>();
        count(list, counter);
        System.out.println("客户红包中奖率：" + counter);
        list.clear();
        counter.clear();

        for (int i = 0; i < 10000; i++) {
            list.add(getAuditorHongbaoAmount());
        }
        counter = new HashMap<>();
        count(list, counter);
        System.out.println("审核人员红包中奖率：" + counter);
    }

    private static void count(List<Double> list, Map<String, Integer> counter) {
        for (Double aDouble : list) {
            Integer count = counter.get(aDouble.toString());
            if (count == null) {
                count = 0;
            }
            count += 1;
            counter.put(aDouble.toString(), count);
        }
    }
}
